package com.example.javapoet.demo.intermediate;

import com.squareup.javapoet.*;
import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;

import javax.lang.model.element.Modifier;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * JavaPoet中级示例 - 生成包含控制流语句的代码
 */
public class ControlFlowGeneration {

    public static void main(String[] args) {
        // 生成包含if-else语句的代码
        generateIfElseStatements();
        
        // 生成包含循环语句的代码
        generateLoopStatements();
        
        // 生成包含switch语句的代码
        generateSwitchStatements();
        
        // 生成包含try-catch语句的代码
        generateTryCatchStatements();
    }

    /**
     * 生成包含if-else语句的代码
     */
    public static void generateIfElseStatements() {
        // 创建方法
        MethodSpec validateMethod = MethodSpec.methodBuilder("validate")
                .addModifiers(Modifier.PUBLIC)
                .returns(boolean.class)
                .addParameter(String.class, "input")
                .beginControlFlow("if (input == null)")
                .addStatement("return false")
                .endControlFlow()
                .beginControlFlow("if (input.isEmpty())")
                .addStatement("return false")
                .endControlFlow()
                .beginControlFlow("if (input.length() < 3)")
                .addStatement("return false")
                .nextControlFlow("else if (input.length() > 100)")
                .addStatement("return false")
                .nextControlFlow("else")
                .addStatement("return true")
                .endControlFlow()
                .build();
        
        MethodSpec checkPermissionMethod = MethodSpec.methodBuilder("checkPermission")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addParameter(String.class, "role")
                .addParameter(boolean.class, "isAdmin")
                .beginControlFlow("if (isAdmin)")
                .addStatement("return $S", "GRANTED")
                .nextControlFlow("else if ($S.equals(role))", "MANAGER")
                .addStatement("return $S", "GRANTED")
                .nextControlFlow("else if ($S.equals(role))", "USER")
                .beginControlFlow("if (hasBasicPermission())")
                .addStatement("return $S", "LIMITED")
                .nextControlFlow("else")
                .addStatement("return $S", "DENIED")
                .endControlFlow()
                .nextControlFlow("else")
                .addStatement("return $S", "DENIED")
                .endControlFlow()
                .build();
        
        MethodSpec hasBasicPermissionMethod = MethodSpec.methodBuilder("hasBasicPermission")
                .addModifiers(Modifier.PRIVATE)
                .returns(boolean.class)
                .addStatement("return true")
                .build();
        
        // 创建类
        TypeSpec validatorClass = TypeSpec.classBuilder("Validator")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(validateMethod)
                .addMethod(checkPermissionMethod)
                .addMethod(hasBasicPermissionMethod)
                .build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.controlflow", validatorClass)
                .build();

        try {
            // 输出到控制台
            System.out.println("生成Validator类（包含if-else语句）:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成Validator.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成包含循环语句的代码
     */
    public static void generateLoopStatements() {
        // 创建方法
        MethodSpec processArrayMethod = MethodSpec.methodBuilder("processArray")
                .addModifiers(Modifier.PUBLIC)
                .returns(int.class)
                .addParameter(ArrayTypeName.of(int.class), "array")
                .addStatement("int sum = 0")
                .beginControlFlow("for (int i = 0; i < array.length; i++)")
                .addStatement("sum += array[i]")
                .endControlFlow()
                .addStatement("return sum")
                .build();
        
        MethodSpec processListMethod = MethodSpec.methodBuilder("processList")
                .addModifiers(Modifier.PUBLIC)
                .returns(int.class)
                .addParameter(ParameterizedTypeName.get(
                        ClassName.get(List.class),
                        ClassName.get(Integer.class)), "list")
                .addStatement("int sum = 0")
                .beginControlFlow("for (Integer value : list)")
                .beginControlFlow("if (value != null)")
                .addStatement("sum += value")
                .endControlFlow()
                .endControlFlow()
                .addStatement("return sum")
                .build();
        
        MethodSpec countDownMethod = MethodSpec.methodBuilder("countDown")
                .addModifiers(Modifier.PUBLIC)
                .returns(void.class)
                .addParameter(int.class, "start")
                .addStatement("int i = start")
                .beginControlFlow("while (i > 0)")
                .addStatement("System.out.println(i)")
                .addStatement("i--")
                .endControlFlow()
                .addStatement("System.out.println($S)", "Blast off!")
                .build();
        
        MethodSpec processWithIndexMethod = MethodSpec.methodBuilder("processWithIndex")
                .addModifiers(Modifier.PUBLIC)
                .returns(void.class)
                .addParameter(ParameterizedTypeName.get(
                        ClassName.get(List.class),
                        ClassName.get(String.class)), "items")
                .addStatement("int index = 0")
                .beginControlFlow("do")
                .beginControlFlow("if (index >= items.size())")
                .addStatement("break")
                .endControlFlow()
                .addStatement("System.out.println(items.get(index))")
                .addStatement("index++")
                .endControlFlow("while (true)")
                .build();
        
        // 创建类
        TypeSpec processorClass = TypeSpec.classBuilder("Processor")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(processArrayMethod)
                .addMethod(processListMethod)
                .addMethod(countDownMethod)
                .addMethod(processWithIndexMethod)
                .build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.controlflow", processorClass)
                .build();

        try {
            // 输出到控制台
            System.out.println("\n生成Processor类（包含循环语句）:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成Processor.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成包含switch语句的代码
     */
    public static void generateSwitchStatements() {
        // 创建方法
        MethodSpec getDayNameMethod = MethodSpec.methodBuilder("getDayName")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addParameter(int.class, "day")
                .beginControlFlow("switch (day)")
                .addStatement("case 1: return $S", "Monday")
                .addStatement("case 2: return $S", "Tuesday")
                .addStatement("case 3: return $S", "Wednesday")
                .addStatement("case 4: return $S", "Thursday")
                .addStatement("case 5: return $S", "Friday")
                .addStatement("case 6: return $S", "Saturday")
                .addStatement("case 7: return $S", "Sunday")
                .addStatement("default: return $S", "Invalid day")
                .endControlFlow()
                .build();
        
        MethodSpec getQuarterMethod = MethodSpec.methodBuilder("getQuarter")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addParameter(int.class, "month")
                .beginControlFlow("switch (month)")
                .beginControlFlow("case 1: case 2: case 3:")
                .addStatement("return $S", "Q1")
                .endControlFlow()
                .beginControlFlow("case 4: case 5: case 6:")
                .addStatement("return $S", "Q2")
                .endControlFlow()
                .beginControlFlow("case 7: case 8: case 9:")
                .addStatement("return $S", "Q3")
                .endControlFlow()
                .beginControlFlow("case 10: case 11: case 12:")
                .addStatement("return $S", "Q4")
                .endControlFlow()
                .beginControlFlow("default:")
                .addStatement("throw new $T($S + month)", IllegalArgumentException.class, "Invalid month: ")
                .endControlFlow()
                .build();
        
        // Java 12+ switch表达式风格（JavaPoet会生成兼容的代码）
        MethodSpec getSeasonMethod = MethodSpec.methodBuilder("getSeason")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addParameter(int.class, "month")
                .addStatement("String season")
                .beginControlFlow("switch (month)")
                .beginControlFlow("case 12: case 1: case 2:")
                .addStatement("season = $S", "Winter")
                .addStatement("break")
                .endControlFlow()
                .beginControlFlow("case 3: case 4: case 5:")
                .addStatement("season = $S", "Spring")
                .addStatement("break")
                .endControlFlow()
                .beginControlFlow("case 6: case 7: case 8:")
                .addStatement("season = $S", "Summer")
                .addStatement("break")
                .endControlFlow()
                .beginControlFlow("case 9: case 10: case 11:")
                .addStatement("season = $S", "Fall")
                .addStatement("break")
                .endControlFlow()
                .beginControlFlow("default:")
                .addStatement("season = $S", "Unknown")
                .endControlFlow()
                .addStatement("return season")
                .build();
        
        // 创建类
        TypeSpec calendarHelperClass = TypeSpec.classBuilder("CalendarHelper")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(getDayNameMethod)
                .addMethod(getQuarterMethod)
                .addMethod(getSeasonMethod)
                .build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.controlflow", calendarHelperClass)
                .build();

        try {
            // 输出到控制台
            System.out.println("\n生成CalendarHelper类（包含switch语句）:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成CalendarHelper.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成包含try-catch语句的代码
     */
    public static void generateTryCatchStatements() {
        // 创建方法
        MethodSpec parseIntMethod = MethodSpec.methodBuilder("parseInt")
                .addModifiers(Modifier.PUBLIC)
                .returns(int.class)
                .addParameter(String.class, "input")
                .beginControlFlow("try")
                .addStatement("return $T.parseInt(input)", Integer.class)
                .nextControlFlow("catch ($T e)", NumberFormatException.class)
                .addStatement("System.err.println($S + input)", "Failed to parse: ")
                .addStatement("return 0")
                .endControlFlow()
                .build();
        
        MethodSpec readFileMethod = MethodSpec.methodBuilder("readFile")
                .addModifiers(Modifier.PUBLIC)
                .returns(String.class)
                .addParameter(String.class, "path")
                .addException(IOException.class)
                .beginControlFlow("try ($T reader = new $T(path))", 
                        ClassName.get("java.io", "BufferedReader"),
                        ClassName.get("java.io", "FileReader"))
                .addStatement("$T content = new $T()", StringBuilder.class, StringBuilder.class)
                .addStatement("String line")
                .beginControlFlow("while ((line = reader.readLine()) != null)")
                .addStatement("content.append(line).append($S)", "\\n")
                .endControlFlow()
                .addStatement("return content.toString()")
                .endControlFlow()
                .build();
        
        MethodSpec executeWithRetryMethod = MethodSpec.methodBuilder("executeWithRetry")
                .addModifiers(Modifier.PUBLIC)
                .returns(boolean.class)
                //.addParameter(ClassName.get("java.util.function", "Supplier").parameterizedBy(TypeName.BOOLEAN), "action")
                .addParameter(int.class, "maxRetries")
                .addStatement("int attempts = 0")
                .beginControlFlow("while (attempts < maxRetries)")
                .beginControlFlow("try")
                .addStatement("boolean result = action.get()")
                .beginControlFlow("if (result)")
                .addStatement("return true")
                .endControlFlow()
                .nextControlFlow("catch ($T e)", Exception.class)
                .addStatement("attempts++")
                .addStatement("System.err.println($S + attempts + $S + e.getMessage())", 
                        "Attempt ", " failed: ")
                .beginControlFlow("try")
                .addStatement("$T.sleep(1000 * attempts)", TimeUnit.class)
                .nextControlFlow("catch ($T e2)", InterruptedException.class)
                .addStatement("Thread.currentThread().interrupt()")
                .endControlFlow()
                .addStatement("continue")
                .endControlFlow()
                .addStatement("attempts++")
                .endControlFlow()
                .addStatement("return false")
                .build();
        
        MethodSpec processResourceMethod = MethodSpec.methodBuilder("processResource")
                .addModifiers(Modifier.PUBLIC)
                .returns(void.class)
                .addParameter(ClassName.get("java.io", "Closeable"), "resource")
                .beginControlFlow("try")
                .addStatement("// 使用资源")
                .addStatement("System.out.println($S)", "Processing resource...")
                .nextControlFlow("finally")
                .beginControlFlow("if (resource != null)")
                .beginControlFlow("try")
                .addStatement("resource.close()")
                .nextControlFlow("catch ($T e)", IOException.class)
                .addStatement("System.err.println($S)", "Failed to close resource")
                .endControlFlow()
                .endControlFlow()
                .endControlFlow()
                .build();
        
        // 创建类
        TypeSpec errorHandlerClass = TypeSpec.classBuilder("ErrorHandler")
                .addModifiers(Modifier.PUBLIC)
                .addMethod(parseIntMethod)
                .addMethod(readFileMethod)
                .addMethod(executeWithRetryMethod)
                .addMethod(processResourceMethod)
                .build();
        
        // 创建Java文件
        JavaFile javaFile = JavaFile.builder("com.example.controlflow", errorHandlerClass)
                .build();

        try {
            // 输出到控制台
            System.out.println("\n生成ErrorHandler类（包含try-catch语句）:");
            javaFile.writeTo(System.out);
            
            // 输出到文件
            Path path = Paths.get("src/main/java");
            javaFile.writeTo(new File(path.toUri()));
            System.out.println("成功生成ErrorHandler.java文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}